# Instalación de paquetes (ejecutar solo una vez)
install.packages(c("tidyverse", "plotly", "scales", "lubridate",
"corrplot", "gridExtra", "hrbrthemes", "stats"))
# Cargar librerÃas
library(tidyverse) # Para manipulación de datos y visualización
library(plotly) # Para gráficos interactivos
library(scales) # Para formateo de escalas
library(lubridate) # Para manejo de fechas
library(corrplot) # Para matrices de correlación
library(gridExtra) # Para combinar gráficos
library(hrbrthemes) # Para temas de visualización
library(stats) # Para análisis estadÃstico
if (!requireNamespace("dplyr", quietly = TRUE)) install.packages("dplyr")
if (!requireNamespace("ggplot2", quietly = TRUE)) install.packages("ggplot2")
if (!requireNamespace("plotly", quietly = TRUE)) install.packages("plotly")
if (!requireNamespace("hrbrthemes", quietly = TRUE)) install.packages("hrbrthemes")
library(dplyr)
library(ggplot2)
library(plotly)
library(hrbrthemes)
#Cargar datos
library(readr)
datos <- read_csv("C:/Users/akege/Downloads/enhanced_saas_marketing_data (1).csv")
Rows: 1152 Columns: 38
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): company, region, product_category
dbl (34): organic_traffic, direct_traffic, referral_traffic, paid_traffic, ...
date (1): date
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
View(enhanced_saas_marketing_data_1_)
# Preparación inicial de datos
datos_prep <- datos %>%
# Convertir fecha a formato Date
mutate(
date = as.Date(date),
month = floor_date(date, "month"),
# Crear métricas derivadas
gross_margin = (revenue - costs) / revenue,
marketing_efficiency = revenue / marketing_spend,
clv_cac_ratio = customer_lifetime_value / customer_acquisition_cost
)
# Verificar estructura de datos
str(datos_prep)
tibble [1,152 × 41] (S3: tbl_df/tbl/data.frame)
$ date : Date[1:1152], format: "2022-01-31" "2022-01-31" ...
$ company : chr [1:1152] "SaasCompany1" "SaasCompany1" "SaasCompany1" "SaasCompany1" ...
$ region : chr [1:1152] "North" "North" "North" "South" ...
$ product_category : chr [1:1152] "Enterprise" "SMB" "Startup" "Enterprise" ...
$ organic_traffic : num [1:1152] 162835 130162 119058 171379 183703 ...
$ direct_traffic : num [1:1152] 62183 53651 51618 64307 71783 ...
$ referral_traffic : num [1:1152] 31091 26825 25809 32153 35891 ...
$ paid_traffic : num [1:1152] 46637 40238 38713 48230 53837 ...
$ bounce_rate : num [1:1152] 0.543 0.485 0.49 0.49 0.509 ...
$ avg_session_duration : num [1:1152] 217 121 190 269 289 ...
$ pages_per_session : num [1:1152] 2.29 4.62 4.75 4.6 3.62 ...
$ conversion_rate : num [1:1152] 0.0478 0.0443 0.0421 0.0486 0.0467 ...
$ email_sends : num [1:1152] 11543 9195 10509 6031 7723 ...
$ email_opens : num [1:1152] 2931 3616 5807 5901 6556 ...
$ email_clicks : num [1:1152] 541 621 844 1007 1307 ...
$ social_posts : num [1:1152] 42 38 35 46 40 43 41 45 24 22 ...
$ social_engagement : num [1:1152] 4028 3242 3473 4405 3405 ...
$ leads_generated : num [1:1152] 110 138 118 231 245 126 224 202 171 121 ...
$ qualified_leads : num [1:1152] 61 87 103 72 119 149 63 126 86 147 ...
$ opportunities : num [1:1152] 45 25 36 42 24 30 49 27 23 58 ...
$ closed_deals : num [1:1152] 6 19 23 17 19 12 20 14 9 14 ...
$ revenue : num [1:1152] 59099 125413 147662 83751 84552 ...
$ costs : num [1:1152] 40391 34093 34674 88972 49400 ...
$ marketing_spend : num [1:1152] 10403 10689 29984 20573 15177 ...
$ customer_acquisition_cost: num [1:1152] 160 137 286 153 155 ...
$ customer_lifetime_value : num [1:1152] 2331 1060 2388 1951 1224 ...
$ nps : num [1:1152] 50.1 32.5 53.9 76.1 45.5 ...
$ customer_satisfaction : num [1:1152] 8.57 9.01 7.99 8.59 8.31 ...
$ support_tickets : num [1:1152] 191 82 152 65 102 159 98 133 50 87 ...
$ resolution_time : num [1:1152] 13.1 30.2 34.7 20.2 37.7 ...
$ active_users : num [1:1152] 1117 3020 1537 3991 4302 ...
$ feature_adoption_rate : num [1:1152] 0.509 0.613 0.608 0.628 0.444 ...
$ churn_rate : num [1:1152] 0.0405 0.0313 0.0131 0.0495 0.0315 ...
$ expansion_revenue : num [1:1152] 8481 9342 11986 13743 11903 ...
$ gross_margin : num [1:1152] 0.3166 0.7282 0.7652 -0.0623 0.4157 ...
$ marketing_roi : num [1:1152] 4.68 10.73 3.92 3.07 4.57 ...
$ conversion_to_paid : num [1:1152] 0.0545 0.1377 0.1949 0.0736 0.0776 ...
$ email_engagement_rate : num [1:1152] 0.0469 0.0675 0.0803 0.167 0.1692 ...
$ month : Date[1:1152], format: "2022-01-01" "2022-01-01" ...
$ marketing_efficiency : num [1:1152] 5.68 11.73 4.92 4.07 5.57 ...
$ clv_cac_ratio : num [1:1152] 14.61 7.76 8.35 12.72 7.91 ...
summary(datos_prep)
date company region product_category
Min. :2022-01-31 Length:1152 Length:1152 Length:1152
1st Qu.:2022-07-23 Class :character Class :character Class :character
Median :2023-01-15 Mode :character Mode :character Mode :character
Mean :2023-01-14
3rd Qu.:2023-07-07
Max. :2023-12-31
organic_traffic direct_traffic referral_traffic paid_traffic
Min. : 50255 Min. : 20738 Min. :10369 Min. :15554
1st Qu.: 97689 1st Qu.: 39133 1st Qu.:19566 1st Qu.:29350
Median :138657 Median : 55192 Median :27596 Median :41394
Mean :143115 Mean : 57175 Mean :28587 Mean :42881
3rd Qu.:182241 3rd Qu.: 71952 3rd Qu.:35976 3rd Qu.:53964
Max. :287367 Max. :117133 Max. :58566 Max. :87850
bounce_rate avg_session_duration pages_per_session conversion_rate
Min. :0.3003 Min. :120.0 Min. :2.002 Min. :0.01850
1st Qu.:0.3726 1st Qu.:162.1 1st Qu.:3.001 1st Qu.:0.02552
Median :0.4483 Median :204.4 Median :3.998 Median :0.03170
Mean :0.4488 Mean :206.5 Mean :3.999 Mean :0.03300
3rd Qu.:0.5224 3rd Qu.:249.9 3rd Qu.:5.011 3rd Qu.:0.03992
Max. :0.5999 Max. :299.7 Max. :5.993 Max. :0.05442
email_sends email_opens email_clicks social_posts
Min. : 5003 Min. :2003 Min. : 502.0 Min. :20.00
1st Qu.: 7580 1st Qu.:3525 1st Qu.: 873.8 1st Qu.:27.00
Median :10060 Median :4999 Median :1234.0 Median :35.00
Mean : 9997 Mean :5024 Mean :1236.0 Mean :34.88
3rd Qu.:12494 3rd Qu.:6505 3rd Qu.:1588.5 3rd Qu.:42.00
Max. :14988 Max. :7995 Max. :1998.0 Max. :49.00
social_engagement leads_generated qualified_leads opportunities
Min. :1010 Min. :100.0 Min. : 50.0 Min. :20.00
1st Qu.:2013 1st Qu.:151.0 1st Qu.: 76.0 1st Qu.:29.00
Median :2972 Median :197.0 Median :101.5 Median :39.00
Mean :2976 Mean :198.9 Mean :100.6 Mean :39.04
3rd Qu.:3933 3rd Qu.:246.0 3rd Qu.:125.0 3rd Qu.:49.00
Max. :4999 Max. :299.0 Max. :149.0 Max. :59.00
closed_deals revenue costs marketing_spend
Min. : 5.0 Min. : 50076 Min. :30147 Min. :10002
1st Qu.: 9.0 1st Qu.: 74134 1st Qu.:46084 1st Qu.:14928
Median :14.0 Median : 98584 Median :60305 Median :19706
Mean :14.4 Mean : 99116 Mean :60734 Mean :19819
3rd Qu.:19.0 3rd Qu.:124962 3rd Qu.:76170 3rd Qu.:24649
Max. :24.0 Max. :149830 Max. :89940 Max. :29995
customer_acquisition_cost customer_lifetime_value nps
Min. :100.1 Min. :1002 Min. :30.01
1st Qu.:153.0 1st Qu.:1486 1st Qu.:41.67
Median :199.4 Median :1991 Median :54.04
Mean :200.1 Mean :1991 Mean :54.23
3rd Qu.:249.8 3rd Qu.:2512 3rd Qu.:66.50
Max. :299.9 Max. :3000 Max. :79.97
customer_satisfaction support_tickets resolution_time active_users
Min. :7.006 Min. : 50.00 Min. : 2.022 Min. :1005
1st Qu.:7.626 1st Qu.: 86.75 1st Qu.:13.670 1st Qu.:2000
Median :8.229 Median :123.00 Median :25.354 Median :3034
Mean :8.238 Mean :124.68 Mean :25.265 Mean :3015
3rd Qu.:8.872 3rd Qu.:161.25 3rd Qu.:36.720 3rd Qu.:4016
Max. :9.497 Max. :199.00 Max. :47.987 Max. :4999
feature_adoption_rate churn_rate expansion_revenue gross_margin
Min. :0.4010 Min. :0.01006 Min. : 5009 Min. :-0.7103
1st Qu.:0.4989 1st Qu.:0.01987 1st Qu.: 7519 1st Qu.: 0.1753
Median :0.5925 Median :0.03051 Median :10062 Median : 0.3835
Mean :0.5976 Mean :0.03001 Mean :10082 Mean : 0.3273
3rd Qu.:0.6994 3rd Qu.:0.03981 3rd Qu.:12754 3rd Qu.: 0.5472
Max. :0.7998 Max. :0.05000 Max. :14999 Max. : 0.7876
marketing_roi conversion_to_paid email_engagement_rate
Min. : 0.6938 Min. :0.01678 Min. :0.03404
1st Qu.: 2.6859 1st Qu.:0.04724 1st Qu.:0.08718
Median : 4.0063 Median :0.07238 Median :0.12259
Mean : 4.5028 Mean :0.07907 Mean :0.13593
3rd Qu.: 5.8268 3rd Qu.:0.10206 3rd Qu.:0.17436
Max. :12.7085 Max. :0.23301 Max. :0.37791
month marketing_efficiency clv_cac_ratio
Min. :2022-01-01 Min. : 1.694 Min. : 3.409
1st Qu.:2022-06-23 1st Qu.: 3.686 1st Qu.: 7.431
Median :2022-12-16 Median : 5.006 Median : 9.925
Mean :2022-12-16 Mean : 5.503 Mean :10.873
3rd Qu.:2023-06-08 3rd Qu.: 6.827 3rd Qu.:13.366
Max. :2023-12-01 Max. :13.708 Max. :28.844
str(datos_prep)
tibble [1,152 × 41] (S3: tbl_df/tbl/data.frame)
$ date : Date[1:1152], format: "2022-01-31" "2022-01-31" ...
$ company : chr [1:1152] "SaasCompany1" "SaasCompany1" "SaasCompany1" "SaasCompany1" ...
$ region : chr [1:1152] "North" "North" "North" "South" ...
$ product_category : chr [1:1152] "Enterprise" "SMB" "Startup" "Enterprise" ...
$ organic_traffic : num [1:1152] 162835 130162 119058 171379 183703 ...
$ direct_traffic : num [1:1152] 62183 53651 51618 64307 71783 ...
$ referral_traffic : num [1:1152] 31091 26825 25809 32153 35891 ...
$ paid_traffic : num [1:1152] 46637 40238 38713 48230 53837 ...
$ bounce_rate : num [1:1152] 0.543 0.485 0.49 0.49 0.509 ...
$ avg_session_duration : num [1:1152] 217 121 190 269 289 ...
$ pages_per_session : num [1:1152] 2.29 4.62 4.75 4.6 3.62 ...
$ conversion_rate : num [1:1152] 0.0478 0.0443 0.0421 0.0486 0.0467 ...
$ email_sends : num [1:1152] 11543 9195 10509 6031 7723 ...
$ email_opens : num [1:1152] 2931 3616 5807 5901 6556 ...
$ email_clicks : num [1:1152] 541 621 844 1007 1307 ...
$ social_posts : num [1:1152] 42 38 35 46 40 43 41 45 24 22 ...
$ social_engagement : num [1:1152] 4028 3242 3473 4405 3405 ...
$ leads_generated : num [1:1152] 110 138 118 231 245 126 224 202 171 121 ...
$ qualified_leads : num [1:1152] 61 87 103 72 119 149 63 126 86 147 ...
$ opportunities : num [1:1152] 45 25 36 42 24 30 49 27 23 58 ...
$ closed_deals : num [1:1152] 6 19 23 17 19 12 20 14 9 14 ...
$ revenue : num [1:1152] 59099 125413 147662 83751 84552 ...
$ costs : num [1:1152] 40391 34093 34674 88972 49400 ...
$ marketing_spend : num [1:1152] 10403 10689 29984 20573 15177 ...
$ customer_acquisition_cost: num [1:1152] 160 137 286 153 155 ...
$ customer_lifetime_value : num [1:1152] 2331 1060 2388 1951 1224 ...
$ nps : num [1:1152] 50.1 32.5 53.9 76.1 45.5 ...
$ customer_satisfaction : num [1:1152] 8.57 9.01 7.99 8.59 8.31 ...
$ support_tickets : num [1:1152] 191 82 152 65 102 159 98 133 50 87 ...
$ resolution_time : num [1:1152] 13.1 30.2 34.7 20.2 37.7 ...
$ active_users : num [1:1152] 1117 3020 1537 3991 4302 ...
$ feature_adoption_rate : num [1:1152] 0.509 0.613 0.608 0.628 0.444 ...
$ churn_rate : num [1:1152] 0.0405 0.0313 0.0131 0.0495 0.0315 ...
$ expansion_revenue : num [1:1152] 8481 9342 11986 13743 11903 ...
$ gross_margin : num [1:1152] 0.3166 0.7282 0.7652 -0.0623 0.4157 ...
$ marketing_roi : num [1:1152] 4.68 10.73 3.92 3.07 4.57 ...
$ conversion_to_paid : num [1:1152] 0.0545 0.1377 0.1949 0.0736 0.0776 ...
$ email_engagement_rate : num [1:1152] 0.0469 0.0675 0.0803 0.167 0.1692 ...
$ month : Date[1:1152], format: "2022-01-01" "2022-01-01" ...
$ marketing_efficiency : num [1:1152] 5.68 11.73 4.92 4.07 5.57 ...
$ clv_cac_ratio : num [1:1152] 14.61 7.76 8.35 12.72 7.91 ...
# Convertir `date` a formato Date si no lo está
datos <- datos %>%
mutate(date = as.Date(date))
# Confirma el tipo de datos
str(datos)
tibble [1,152 × 38] (S3: tbl_df/tbl/data.frame)
$ date : Date[1:1152], format: "2022-01-31" "2022-01-31" ...
$ company : chr [1:1152] "SaasCompany1" "SaasCompany1" "SaasCompany1" "SaasCompany1" ...
$ region : chr [1:1152] "North" "North" "North" "South" ...
$ product_category : chr [1:1152] "Enterprise" "SMB" "Startup" "Enterprise" ...
$ organic_traffic : num [1:1152] 162835 130162 119058 171379 183703 ...
$ direct_traffic : num [1:1152] 62183 53651 51618 64307 71783 ...
$ referral_traffic : num [1:1152] 31091 26825 25809 32153 35891 ...
$ paid_traffic : num [1:1152] 46637 40238 38713 48230 53837 ...
$ bounce_rate : num [1:1152] 0.543 0.485 0.49 0.49 0.509 ...
$ avg_session_duration : num [1:1152] 217 121 190 269 289 ...
$ pages_per_session : num [1:1152] 2.29 4.62 4.75 4.6 3.62 ...
$ conversion_rate : num [1:1152] 0.0478 0.0443 0.0421 0.0486 0.0467 ...
$ email_sends : num [1:1152] 11543 9195 10509 6031 7723 ...
$ email_opens : num [1:1152] 2931 3616 5807 5901 6556 ...
$ email_clicks : num [1:1152] 541 621 844 1007 1307 ...
$ social_posts : num [1:1152] 42 38 35 46 40 43 41 45 24 22 ...
$ social_engagement : num [1:1152] 4028 3242 3473 4405 3405 ...
$ leads_generated : num [1:1152] 110 138 118 231 245 126 224 202 171 121 ...
$ qualified_leads : num [1:1152] 61 87 103 72 119 149 63 126 86 147 ...
$ opportunities : num [1:1152] 45 25 36 42 24 30 49 27 23 58 ...
$ closed_deals : num [1:1152] 6 19 23 17 19 12 20 14 9 14 ...
$ revenue : num [1:1152] 59099 125413 147662 83751 84552 ...
$ costs : num [1:1152] 40391 34093 34674 88972 49400 ...
$ marketing_spend : num [1:1152] 10403 10689 29984 20573 15177 ...
$ customer_acquisition_cost: num [1:1152] 160 137 286 153 155 ...
$ customer_lifetime_value : num [1:1152] 2331 1060 2388 1951 1224 ...
$ nps : num [1:1152] 50.1 32.5 53.9 76.1 45.5 ...
$ customer_satisfaction : num [1:1152] 8.57 9.01 7.99 8.59 8.31 ...
$ support_tickets : num [1:1152] 191 82 152 65 102 159 98 133 50 87 ...
$ resolution_time : num [1:1152] 13.1 30.2 34.7 20.2 37.7 ...
$ active_users : num [1:1152] 1117 3020 1537 3991 4302 ...
$ feature_adoption_rate : num [1:1152] 0.509 0.613 0.608 0.628 0.444 ...
$ churn_rate : num [1:1152] 0.0405 0.0313 0.0131 0.0495 0.0315 ...
$ expansion_revenue : num [1:1152] 8481 9342 11986 13743 11903 ...
$ gross_margin : num [1:1152] 0.3166 0.7282 0.7652 -0.0623 0.4157 ...
$ marketing_roi : num [1:1152] 4.68 10.73 3.92 3.07 4.57 ...
$ conversion_to_paid : num [1:1152] 0.0545 0.1377 0.1949 0.0736 0.0776 ...
$ email_engagement_rate : num [1:1152] 0.0469 0.0675 0.0803 0.167 0.1692 ...
crear_tendencias <- function(datos, metrica, titulo) {
# Validar que las columnas necesarias existen
validar_columnas(datos, c("date", "company", metrica))
# Convertir `date` a formato Date
datos <- datos %>%
mutate(date = as.Date(date))
# Resumir datos
datos_resumidos <- datos %>%
group_by(date, company) %>%
summarise(valor = mean(!!sym(metrica), na.rm = TRUE), .groups = 'drop')
# Verifica que hay datos
if (nrow(datos_resumidos) == 0) {
stop("No hay datos disponibles para la métrica especificada.")
}
# Crear el gráfico
grafico <- datos_resumidos %>%
ggplot(aes(x = date, y = valor, color = company)) +
geom_line(size = 1) +
geom_point(size = 2) +
theme_ipsum() +
labs(
title = titulo,
x = "Fecha",
y = metrica
) +
theme(legend.position = "bottom")
# Convertir a gráfico interactivo
return(ggplotly(grafico))
}
# Ejemplo de uso
crear_tendencias(datos_prep, "revenue", "Tendencia de Ingresos")
NA
# Función para análisis de distribución
analizar_distribucion <- function(datos, variable) {
# Histograma
hist <- ggplot(datos, aes(x = !!sym(variable), fill = company)) +
geom_histogram(alpha = 0.6, bins = 30) +
facet_wrap(~company, scales = "free") +
theme_minimal() +
labs(title = paste("Distribución de", variable))
# Box plot
box <- ggplot(datos, aes(x = company, y = !!sym(variable), fill = company)) +
geom_boxplot() +
theme_minimal() +
labs(title = paste("Box Plot de", variable)) +
theme(axis.text.x = element_text(angle = 45))
# Combinar gráficos
grid.arrange(hist, box, ncol = 1)
}
# Analizar distribuciones de métricas clave
analizar_distribucion(datos_prep, "revenue")

analizar_distribucion(datos_prep, "customer_lifetime_value")

library(dplyr)
library(purrr)
# Función para análisis estadÃstico por empresa
analisis_estadistico <- function(datos) {
# Asegúrate de que los datos estén agrupados correctamente
resumen <- datos %>%
group_by(company) %>%
summarise(
# Métricas financieras
revenue_mean = mean(revenue, na.rm = TRUE),
revenue_sd = sd(revenue, na.rm = TRUE),
margin_mean = mean(gross_margin, na.rm = TRUE),
# Métricas de cliente
cac_mean = mean(customer_acquisition_cost, na.rm = TRUE),
clv_mean = mean(customer_lifetime_value, na.rm = TRUE),
clv_cac_ratio = mean(clv_cac_ratio, na.rm = TRUE),
# Métricas de engagement
satisfaction_mean = mean(customer_satisfaction, na.rm = TRUE),
churn_rate_mean = mean(churn_rate, na.rm = TRUE),
# Número de observaciones
n = n()
) %>%
# Agregar prueba de normalidad (por separado debido a la naturaleza de shapiro.test)
mutate(
revenue_normality = map_dbl(split(datos$revenue, datos$company),
~ if (length(na.omit(.x)) > 3) shapiro.test(.x)$p.value else NA_real_)
)
return(resumen)
}
# Ejecutar análisis estadÃstico
resumen_estadistico <- analisis_estadistico(datos_prep)
# Mostrar resultados
print(resumen_estadistico)
library(corrplot)
library(dplyr)
analizar_correlaciones <- function(datos, metodo = "pearson", variables = NULL) {
# Seleccionar métricas numéricas
metricas_numericas <- datos %>%
select_if(is.numeric)
# Si se proporcionan variables, seleccionarlas
if (!is.null(variables)) {
metricas_numericas <- metricas_numericas %>%
select(all_of(variables))
}
# Calcular matriz de correlaciones
correlaciones <- cor(metricas_numericas, use = "complete.obs", method = metodo)
# Renombrar columnas con abreviaturas
colnames(correlaciones) <- abbreviate(colnames(correlaciones), minlength = 6)
rownames(correlaciones) <- abbreviate(rownames(correlaciones), minlength = 6)
# Ajustar tamaño del gráfico
par(mar = c(0, 0, 2, 0)) # Márgenes más pequeños
corrplot(correlaciones,
method = "color", # Estilo de color
type = "upper", # Mostrar solo la parte superior
addCoef.col = "black", # Mostrar coeficientes en negro
number.cex = 0.7, # Tamaño de coeficientes
tl.cex = 0.8, # Tamaño de etiquetas
tl.srt = 45, # Rotar etiquetas 45 grados
title = "Matriz de Correlaciones")
}
# Seleccionar un subconjunto de variables para claridad
variables_interes <- c("organic_traffic", "direct_traffic", "referral_traffic",
"paid_traffic", "bounce_rate", "conversion_rate",
"revenue", "marketing_spend", "customer_satisfaction",
"churn_rate")
# Ejecutar análisis de correlaciones con variables seleccionadas
analizar_correlaciones(datos_prep, metodo = "spearman", variables = variables_interes)

library(corrplot)
analizar_correlaciones <- function(datos, metodo = "pearson") {
# Seleccionar métricas numéricas
metricas_numericas <- datos %>%
select_if(is.numeric) # Seleccionar solo columnas numéricas
# Calcular matriz de correlaciones
correlaciones <- cor(metricas_numericas, use = "complete.obs", method = metodo)
# Crear visualización de la matriz de correlaciones con ajustes
corrplot(correlaciones,
method = "color", # Estilo de color para las correlaciones
type = "upper", # Mostrar solo la mitad superior
addCoef.col = "black", # Mostrar valores numéricos en negro
number.cex = 0.6, # Tamaño de los coeficientes numéricos
tl.cex = 0.6, # Tamaño de las etiquetas de texto
tl.col = "blue", # Color de las etiquetas de texto
tl.srt = 45, # Rotar etiquetas 45 grados
title = "Matriz de Correlaciones",
mar = c(0, 0, 2, 0)) # Márgenes del gráfico
}
# Ejecutar análisis de correlaciones
analizar_correlaciones(datos_prep, metodo = "spearman")

NA
NA
library(ggplot2)
library(dplyr)
library(plotly)
analisis_roi <- function(datos) {
# Agrupar y calcular métricas
roi_plot <- datos %>%
group_by(company, month) %>%
summarise(
marketing_roi = mean(marketing_roi, na.rm = TRUE),
marketing_spend = mean(marketing_spend, na.rm = TRUE),
.groups = 'drop' # Evitar mensajes sobre agrupamiento
) %>%
# Crear gráfico
ggplot(aes(x = marketing_spend, y = marketing_roi, color = company)) +
geom_point(size = 3, alpha = 0.6) + # Puntos de datos
geom_smooth(method = "lm", se = FALSE) + # LÃnea de tendencia
theme_minimal() +
labs(
title = "ROI vs Inversión en Marketing",
x = "Inversión en Marketing",
y = "ROI"
) +
theme(
legend.position = "bottom", # Leyenda en la parte inferior
plot.title = element_text(size = 16, face = "bold"),
axis.title = element_text(size = 12)
)
# Convertir gráfico a interactivo con plotly
return(ggplotly(roi_plot))
}
# Visualizar análisis de ROI
grafico_roi <- analisis_roi(datos_prep)
`geom_smooth()` using formula = 'y ~ x'
# Mostrar gráfico interactivo
grafico_roi
NA
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7cn0NCiMgSW5zdGFsYWNpw7NuIGRlIHBhcXVldGVzIChlamVjdXRhciBzb2xvIHVuYSB2ZXopDQppbnN0YWxsLnBhY2thZ2VzKGMoInRpZHl2ZXJzZSIsICJwbG90bHkiLCAic2NhbGVzIiwgImx1YnJpZGF0ZSIsDQogICAgICAgICAgICAgICAgICAiY29ycnBsb3QiLCAiZ3JpZEV4dHJhIiwgImhyYnJ0aGVtZXMiLCAic3RhdHMiKSkNCg0KIyBDYXJnYXIgbGlicmVyw61hcw0KbGlicmFyeSh0aWR5dmVyc2UpICAgICAjIFBhcmEgbWFuaXB1bGFjacOzbiBkZSBkYXRvcyB5IHZpc3VhbGl6YWNpw7NuDQpsaWJyYXJ5KHBsb3RseSkgICAgICAgICMgUGFyYSBncsOhZmljb3MgaW50ZXJhY3Rpdm9zDQpsaWJyYXJ5KHNjYWxlcykgICAgICAgICMgUGFyYSBmb3JtYXRlbyBkZSBlc2NhbGFzDQpsaWJyYXJ5KGx1YnJpZGF0ZSkgICAgICMgUGFyYSBtYW5lam8gZGUgZmVjaGFzDQpsaWJyYXJ5KGNvcnJwbG90KSAgICAgICMgUGFyYSBtYXRyaWNlcyBkZSBjb3JyZWxhY2nDs24NCmxpYnJhcnkoZ3JpZEV4dHJhKSAgICAgIyBQYXJhIGNvbWJpbmFyIGdyw6FmaWNvcw0KbGlicmFyeShocmJydGhlbWVzKSAgICAjIFBhcmEgdGVtYXMgZGUgdmlzdWFsaXphY2nDs24NCmxpYnJhcnkoc3RhdHMpICAgICAgICAgIyBQYXJhIGFuw6FsaXNpcyBlc3RhZMOtc3RpY28NCmBgYA0KDQpgYGB7cn0NCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiZHBseXIiLCBxdWlldGx5ID0gVFJVRSkpIGluc3RhbGwucGFja2FnZXMoImRwbHlyIikNCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiZ2dwbG90MiIsIHF1aWV0bHkgPSBUUlVFKSkgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQppZiAoIXJlcXVpcmVOYW1lc3BhY2UoInBsb3RseSIsIHF1aWV0bHkgPSBUUlVFKSkgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiaHJicnRoZW1lcyIsIHF1aWV0bHkgPSBUUlVFKSkgaW5zdGFsbC5wYWNrYWdlcygiaHJicnRoZW1lcyIpDQoNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoaHJicnRoZW1lcykNCg0KYGBgDQoNCmBgYHtyfQ0KI0NhcmdhciBkYXRvcw0KbGlicmFyeShyZWFkcikNCmRhdG9zIDwtIHJlYWRfY3N2KCJDOi9Vc2Vycy9ha2VnZS9Eb3dubG9hZHMvZW5oYW5jZWRfc2Fhc19tYXJrZXRpbmdfZGF0YSAoMSkuY3N2IikNClZpZXcoZW5oYW5jZWRfc2Fhc19tYXJrZXRpbmdfZGF0YV8xXykNCmBgYA0KDQpgYGB7cn0NCiMgUHJlcGFyYWNpw7NuIGluaWNpYWwgZGUgZGF0b3MNCmRhdG9zX3ByZXAgPC0gZGF0b3MgJT4lDQogICMgQ29udmVydGlyIGZlY2hhIGEgZm9ybWF0byBEYXRlDQogIG11dGF0ZSgNCiAgICBkYXRlID0gYXMuRGF0ZShkYXRlKSwNCiAgICBtb250aCA9IGZsb29yX2RhdGUoZGF0ZSwgIm1vbnRoIiksDQogICAgIyBDcmVhciBtw6l0cmljYXMgZGVyaXZhZGFzDQogICAgZ3Jvc3NfbWFyZ2luID0gKHJldmVudWUgLSBjb3N0cykgLyByZXZlbnVlLA0KICAgIG1hcmtldGluZ19lZmZpY2llbmN5ID0gcmV2ZW51ZSAvIG1hcmtldGluZ19zcGVuZCwNCiAgICBjbHZfY2FjX3JhdGlvID0gY3VzdG9tZXJfbGlmZXRpbWVfdmFsdWUgLyBjdXN0b21lcl9hY3F1aXNpdGlvbl9jb3N0DQogICkNCg0KIyBWZXJpZmljYXIgZXN0cnVjdHVyYSBkZSBkYXRvcw0Kc3RyKGRhdG9zX3ByZXApDQpzdW1tYXJ5KGRhdG9zX3ByZXApDQoNCmBgYA0KDQpgYGB7cn0NCnN0cihkYXRvc19wcmVwKQ0KYGBgDQoNCmBgYHtyfQ0KIyBDb252ZXJ0aXIgYGRhdGVgIGEgZm9ybWF0byBEYXRlIHNpIG5vIGxvIGVzdMOhDQpkYXRvcyA8LSBkYXRvcyAlPiUNCiAgbXV0YXRlKGRhdGUgPSBhcy5EYXRlKGRhdGUpKQ0KDQojIENvbmZpcm1hIGVsIHRpcG8gZGUgZGF0b3MNCnN0cihkYXRvcykNCg0KYGBgDQoNCmBgYHtyfQ0KY3JlYXJfdGVuZGVuY2lhcyA8LSBmdW5jdGlvbihkYXRvcywgbWV0cmljYSwgdGl0dWxvKSB7DQogICMgVmFsaWRhciBxdWUgbGFzIGNvbHVtbmFzIG5lY2VzYXJpYXMgZXhpc3Rlbg0KICB2YWxpZGFyX2NvbHVtbmFzKGRhdG9zLCBjKCJkYXRlIiwgImNvbXBhbnkiLCBtZXRyaWNhKSkNCiAgDQogICMgQ29udmVydGlyIGBkYXRlYCBhIGZvcm1hdG8gRGF0ZQ0KICBkYXRvcyA8LSBkYXRvcyAlPiUNCiAgICBtdXRhdGUoZGF0ZSA9IGFzLkRhdGUoZGF0ZSkpDQogIA0KICAjIFJlc3VtaXIgZGF0b3MNCiAgZGF0b3NfcmVzdW1pZG9zIDwtIGRhdG9zICU+JQ0KICAgIGdyb3VwX2J5KGRhdGUsIGNvbXBhbnkpICU+JQ0KICAgIHN1bW1hcmlzZSh2YWxvciA9IG1lYW4oISFzeW0obWV0cmljYSksIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAnZHJvcCcpDQogIA0KICAjIFZlcmlmaWNhIHF1ZSBoYXkgZGF0b3MNCiAgaWYgKG5yb3coZGF0b3NfcmVzdW1pZG9zKSA9PSAwKSB7DQogICAgc3RvcCgiTm8gaGF5IGRhdG9zIGRpc3BvbmlibGVzIHBhcmEgbGEgbcOpdHJpY2EgZXNwZWNpZmljYWRhLiIpDQogIH0NCiAgDQogICMgQ3JlYXIgZWwgZ3LDoWZpY28NCiAgZ3JhZmljbyA8LSBkYXRvc19yZXN1bWlkb3MgJT4lDQogICAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IHZhbG9yLCBjb2xvciA9IGNvbXBhbnkpKSArDQogICAgZ2VvbV9saW5lKHNpemUgPSAxKSArDQogICAgZ2VvbV9wb2ludChzaXplID0gMikgKw0KICAgIHRoZW1lX2lwc3VtKCkgKw0KICAgIGxhYnMoDQogICAgICB0aXRsZSA9IHRpdHVsbywNCiAgICAgIHggPSAiRmVjaGEiLA0KICAgICAgeSA9IG1ldHJpY2ENCiAgICApICsNCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikNCiAgDQogICMgQ29udmVydGlyIGEgZ3LDoWZpY28gaW50ZXJhY3Rpdm8NCiAgcmV0dXJuKGdncGxvdGx5KGdyYWZpY28pKQ0KfQ0KDQojIEVqZW1wbG8gZGUgdXNvDQpjcmVhcl90ZW5kZW5jaWFzKGRhdG9zX3ByZXAsICJyZXZlbnVlIiwgIlRlbmRlbmNpYSBkZSBJbmdyZXNvcyIpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBGdW5jacOzbiBwYXJhIGFuw6FsaXNpcyBkZSBkaXN0cmlidWNpw7NuDQphbmFsaXphcl9kaXN0cmlidWNpb24gPC0gZnVuY3Rpb24oZGF0b3MsIHZhcmlhYmxlKSB7DQogICMgSGlzdG9ncmFtYQ0KICBoaXN0IDwtIGdncGxvdChkYXRvcywgYWVzKHggPSAhIXN5bSh2YXJpYWJsZSksIGZpbGwgPSBjb21wYW55KSkgKw0KICAgIGdlb21faGlzdG9ncmFtKGFscGhhID0gMC42LCBiaW5zID0gMzApICsNCiAgICBmYWNldF93cmFwKH5jb21wYW55LCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgICB0aGVtZV9taW5pbWFsKCkgKw0KICAgIGxhYnModGl0bGUgPSBwYXN0ZSgiRGlzdHJpYnVjacOzbiBkZSIsIHZhcmlhYmxlKSkNCg0KICAjIEJveCBwbG90DQogIGJveCA8LSBnZ3Bsb3QoZGF0b3MsIGFlcyh4ID0gY29tcGFueSwgeSA9ICEhc3ltKHZhcmlhYmxlKSwgZmlsbCA9IGNvbXBhbnkpKSArDQogICAgZ2VvbV9ib3hwbG90KCkgKw0KICAgIHRoZW1lX21pbmltYWwoKSArDQogICAgbGFicyh0aXRsZSA9IHBhc3RlKCJCb3ggUGxvdCBkZSIsIHZhcmlhYmxlKSkgKw0KICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKQ0KDQogICMgQ29tYmluYXIgZ3LDoWZpY29zDQogIGdyaWQuYXJyYW5nZShoaXN0LCBib3gsIG5jb2wgPSAxKQ0KfQ0KDQojIEFuYWxpemFyIGRpc3RyaWJ1Y2lvbmVzIGRlIG3DqXRyaWNhcyBjbGF2ZQ0KYW5hbGl6YXJfZGlzdHJpYnVjaW9uKGRhdG9zX3ByZXAsICJyZXZlbnVlIikNCmFuYWxpemFyX2Rpc3RyaWJ1Y2lvbihkYXRvc19wcmVwLCAiY3VzdG9tZXJfbGlmZXRpbWVfdmFsdWUiKQ0KDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShwdXJycikNCg0KIyBGdW5jacOzbiBwYXJhIGFuw6FsaXNpcyBlc3RhZMOtc3RpY28gcG9yIGVtcHJlc2ENCmFuYWxpc2lzX2VzdGFkaXN0aWNvIDwtIGZ1bmN0aW9uKGRhdG9zKSB7DQogICMgQXNlZ8O6cmF0ZSBkZSBxdWUgbG9zIGRhdG9zIGVzdMOpbiBhZ3J1cGFkb3MgY29ycmVjdGFtZW50ZQ0KICByZXN1bWVuIDwtIGRhdG9zICU+JQ0KICAgIGdyb3VwX2J5KGNvbXBhbnkpICU+JQ0KICAgIHN1bW1hcmlzZSgNCiAgICAgICMgTcOpdHJpY2FzIGZpbmFuY2llcmFzDQogICAgICByZXZlbnVlX21lYW4gPSBtZWFuKHJldmVudWUsIG5hLnJtID0gVFJVRSksDQogICAgICByZXZlbnVlX3NkID0gc2QocmV2ZW51ZSwgbmEucm0gPSBUUlVFKSwNCiAgICAgIG1hcmdpbl9tZWFuID0gbWVhbihncm9zc19tYXJnaW4sIG5hLnJtID0gVFJVRSksDQogICAgICANCiAgICAgICMgTcOpdHJpY2FzIGRlIGNsaWVudGUNCiAgICAgIGNhY19tZWFuID0gbWVhbihjdXN0b21lcl9hY3F1aXNpdGlvbl9jb3N0LCBuYS5ybSA9IFRSVUUpLA0KICAgICAgY2x2X21lYW4gPSBtZWFuKGN1c3RvbWVyX2xpZmV0aW1lX3ZhbHVlLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgY2x2X2NhY19yYXRpbyA9IG1lYW4oY2x2X2NhY19yYXRpbywgbmEucm0gPSBUUlVFKSwNCg0KICAgICAgIyBNw6l0cmljYXMgZGUgZW5nYWdlbWVudA0KICAgICAgc2F0aXNmYWN0aW9uX21lYW4gPSBtZWFuKGN1c3RvbWVyX3NhdGlzZmFjdGlvbiwgbmEucm0gPSBUUlVFKSwNCiAgICAgIGNodXJuX3JhdGVfbWVhbiA9IG1lYW4oY2h1cm5fcmF0ZSwgbmEucm0gPSBUUlVFKSwNCiAgICAgIA0KICAgICAgIyBOw7ptZXJvIGRlIG9ic2VydmFjaW9uZXMNCiAgICAgIG4gPSBuKCkNCiAgICApICU+JQ0KICAgICMgQWdyZWdhciBwcnVlYmEgZGUgbm9ybWFsaWRhZCAocG9yIHNlcGFyYWRvIGRlYmlkbyBhIGxhIG5hdHVyYWxlemEgZGUgc2hhcGlyby50ZXN0KQ0KICAgIG11dGF0ZSgNCiAgICAgIHJldmVudWVfbm9ybWFsaXR5ID0gbWFwX2RibChzcGxpdChkYXRvcyRyZXZlbnVlLCBkYXRvcyRjb21wYW55KSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiBpZiAobGVuZ3RoKG5hLm9taXQoLngpKSA+IDMpIHNoYXBpcm8udGVzdCgueCkkcC52YWx1ZSBlbHNlIE5BX3JlYWxfKQ0KICAgICkNCiAgDQogIHJldHVybihyZXN1bWVuKQ0KfQ0KDQojIEVqZWN1dGFyIGFuw6FsaXNpcyBlc3RhZMOtc3RpY28NCnJlc3VtZW5fZXN0YWRpc3RpY28gPC0gYW5hbGlzaXNfZXN0YWRpc3RpY28oZGF0b3NfcHJlcCkNCg0KIyBNb3N0cmFyIHJlc3VsdGFkb3MNCnByaW50KHJlc3VtZW5fZXN0YWRpc3RpY28pDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGNvcnJwbG90KQ0KbGlicmFyeShkcGx5cikNCg0KYW5hbGl6YXJfY29ycmVsYWNpb25lcyA8LSBmdW5jdGlvbihkYXRvcywgbWV0b2RvID0gInBlYXJzb24iLCB2YXJpYWJsZXMgPSBOVUxMKSB7DQogICMgU2VsZWNjaW9uYXIgbcOpdHJpY2FzIG51bcOpcmljYXMNCiAgbWV0cmljYXNfbnVtZXJpY2FzIDwtIGRhdG9zICU+JQ0KICAgIHNlbGVjdF9pZihpcy5udW1lcmljKQ0KICANCiAgIyBTaSBzZSBwcm9wb3JjaW9uYW4gdmFyaWFibGVzLCBzZWxlY2Npb25hcmxhcw0KICBpZiAoIWlzLm51bGwodmFyaWFibGVzKSkgew0KICAgIG1ldHJpY2FzX251bWVyaWNhcyA8LSBtZXRyaWNhc19udW1lcmljYXMgJT4lDQogICAgICBzZWxlY3QoYWxsX29mKHZhcmlhYmxlcykpDQogIH0NCg0KICAjIENhbGN1bGFyIG1hdHJpeiBkZSBjb3JyZWxhY2lvbmVzDQogIGNvcnJlbGFjaW9uZXMgPC0gY29yKG1ldHJpY2FzX251bWVyaWNhcywgdXNlID0gImNvbXBsZXRlLm9icyIsIG1ldGhvZCA9IG1ldG9kbykNCg0KICAjIFJlbm9tYnJhciBjb2x1bW5hcyBjb24gYWJyZXZpYXR1cmFzDQogIGNvbG5hbWVzKGNvcnJlbGFjaW9uZXMpIDwtIGFiYnJldmlhdGUoY29sbmFtZXMoY29ycmVsYWNpb25lcyksIG1pbmxlbmd0aCA9IDYpDQogIHJvd25hbWVzKGNvcnJlbGFjaW9uZXMpIDwtIGFiYnJldmlhdGUocm93bmFtZXMoY29ycmVsYWNpb25lcyksIG1pbmxlbmd0aCA9IDYpDQoNCiAgIyBBanVzdGFyIHRhbWHDsW8gZGVsIGdyw6FmaWNvDQogIHBhcihtYXIgPSBjKDAsIDAsIDIsIDApKSAjIE3DoXJnZW5lcyBtw6FzIHBlcXVlw7Fvcw0KICBjb3JycGxvdChjb3JyZWxhY2lvbmVzLA0KICAgICAgICAgICBtZXRob2QgPSAiY29sb3IiLCAgICAgICAgICMgRXN0aWxvIGRlIGNvbG9yDQogICAgICAgICAgIHR5cGUgPSAidXBwZXIiLCAgICAgICAgICAgIyBNb3N0cmFyIHNvbG8gbGEgcGFydGUgc3VwZXJpb3INCiAgICAgICAgICAgYWRkQ29lZi5jb2wgPSAiYmxhY2siLCAgICAjIE1vc3RyYXIgY29lZmljaWVudGVzIGVuIG5lZ3JvDQogICAgICAgICAgIG51bWJlci5jZXggPSAwLjcsICAgICAgICAgIyBUYW1hw7FvIGRlIGNvZWZpY2llbnRlcw0KICAgICAgICAgICB0bC5jZXggPSAwLjgsICAgICAgICAgICAgICMgVGFtYcOxbyBkZSBldGlxdWV0YXMNCiAgICAgICAgICAgdGwuc3J0ID0gNDUsICAgICAgICAgICAgICAjIFJvdGFyIGV0aXF1ZXRhcyA0NSBncmFkb3MNCiAgICAgICAgICAgdGl0bGUgPSAiTWF0cml6IGRlIENvcnJlbGFjaW9uZXMiKQ0KfQ0KDQojIFNlbGVjY2lvbmFyIHVuIHN1YmNvbmp1bnRvIGRlIHZhcmlhYmxlcyBwYXJhIGNsYXJpZGFkDQp2YXJpYWJsZXNfaW50ZXJlcyA8LSBjKCJvcmdhbmljX3RyYWZmaWMiLCAiZGlyZWN0X3RyYWZmaWMiLCAicmVmZXJyYWxfdHJhZmZpYyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAicGFpZF90cmFmZmljIiwgImJvdW5jZV9yYXRlIiwgImNvbnZlcnNpb25fcmF0ZSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAicmV2ZW51ZSIsICJtYXJrZXRpbmdfc3BlbmQiLCAiY3VzdG9tZXJfc2F0aXNmYWN0aW9uIiwgDQogICAgICAgICAgICAgICAgICAgICAgICJjaHVybl9yYXRlIikNCg0KIyBFamVjdXRhciBhbsOhbGlzaXMgZGUgY29ycmVsYWNpb25lcyBjb24gdmFyaWFibGVzIHNlbGVjY2lvbmFkYXMNCmFuYWxpemFyX2NvcnJlbGFjaW9uZXMoZGF0b3NfcHJlcCwgbWV0b2RvID0gInNwZWFybWFuIiwgdmFyaWFibGVzID0gdmFyaWFibGVzX2ludGVyZXMpDQoNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoY29ycnBsb3QpDQoNCmFuYWxpemFyX2NvcnJlbGFjaW9uZXMgPC0gZnVuY3Rpb24oZGF0b3MsIG1ldG9kbyA9ICJwZWFyc29uIikgew0KICAjIFNlbGVjY2lvbmFyIG3DqXRyaWNhcyBudW3DqXJpY2FzDQogIG1ldHJpY2FzX251bWVyaWNhcyA8LSBkYXRvcyAlPiUNCiAgICBzZWxlY3RfaWYoaXMubnVtZXJpYykgICMgU2VsZWNjaW9uYXIgc29sbyBjb2x1bW5hcyBudW3DqXJpY2FzDQoNCiAgIyBDYWxjdWxhciBtYXRyaXogZGUgY29ycmVsYWNpb25lcw0KICBjb3JyZWxhY2lvbmVzIDwtIGNvcihtZXRyaWNhc19udW1lcmljYXMsIHVzZSA9ICJjb21wbGV0ZS5vYnMiLCBtZXRob2QgPSBtZXRvZG8pDQoNCiAgIyBDcmVhciB2aXN1YWxpemFjacOzbiBkZSBsYSBtYXRyaXogZGUgY29ycmVsYWNpb25lcyBjb24gYWp1c3Rlcw0KICBjb3JycGxvdChjb3JyZWxhY2lvbmVzLA0KICAgICAgICAgICBtZXRob2QgPSAiY29sb3IiLCAgICAgICAgICMgRXN0aWxvIGRlIGNvbG9yIHBhcmEgbGFzIGNvcnJlbGFjaW9uZXMNCiAgICAgICAgICAgdHlwZSA9ICJ1cHBlciIsICAgICAgICAgICAjIE1vc3RyYXIgc29sbyBsYSBtaXRhZCBzdXBlcmlvcg0KICAgICAgICAgICBhZGRDb2VmLmNvbCA9ICJibGFjayIsICAgICMgTW9zdHJhciB2YWxvcmVzIG51bcOpcmljb3MgZW4gbmVncm8NCiAgICAgICAgICAgbnVtYmVyLmNleCA9IDAuNiwgICAgICAgICAjIFRhbWHDsW8gZGUgbG9zIGNvZWZpY2llbnRlcyBudW3DqXJpY29zDQogICAgICAgICAgIHRsLmNleCA9IDAuNiwgICAgICAgICAgICAgIyBUYW1hw7FvIGRlIGxhcyBldGlxdWV0YXMgZGUgdGV4dG8NCiAgICAgICAgICAgdGwuY29sID0gImJsdWUiLCAgICAgICAgICAjIENvbG9yIGRlIGxhcyBldGlxdWV0YXMgZGUgdGV4dG8NCiAgICAgICAgICAgdGwuc3J0ID0gNDUsICAgICAgICAgICAgICAjIFJvdGFyIGV0aXF1ZXRhcyA0NSBncmFkb3MNCiAgICAgICAgICAgdGl0bGUgPSAiTWF0cml6IGRlIENvcnJlbGFjaW9uZXMiLCANCiAgICAgICAgICAgbWFyID0gYygwLCAwLCAyLCAwKSkgICAgICAjIE3DoXJnZW5lcyBkZWwgZ3LDoWZpY28NCn0NCg0KIyBFamVjdXRhciBhbsOhbGlzaXMgZGUgY29ycmVsYWNpb25lcw0KYW5hbGl6YXJfY29ycmVsYWNpb25lcyhkYXRvc19wcmVwLCBtZXRvZG8gPSAic3BlYXJtYW4iKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHBsb3RseSkNCg0KYW5hbGlzaXNfcm9pIDwtIGZ1bmN0aW9uKGRhdG9zKSB7DQogICMgQWdydXBhciB5IGNhbGN1bGFyIG3DqXRyaWNhcw0KICByb2lfcGxvdCA8LSBkYXRvcyAlPiUNCiAgICBncm91cF9ieShjb21wYW55LCBtb250aCkgJT4lDQogICAgc3VtbWFyaXNlKA0KICAgICAgbWFya2V0aW5nX3JvaSA9IG1lYW4obWFya2V0aW5nX3JvaSwgbmEucm0gPSBUUlVFKSwNCiAgICAgIG1hcmtldGluZ19zcGVuZCA9IG1lYW4obWFya2V0aW5nX3NwZW5kLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgLmdyb3VwcyA9ICdkcm9wJyAgIyBFdml0YXIgbWVuc2FqZXMgc29icmUgYWdydXBhbWllbnRvDQogICAgKSAlPiUNCiAgICAjIENyZWFyIGdyw6FmaWNvDQogICAgZ2dwbG90KGFlcyh4ID0gbWFya2V0aW5nX3NwZW5kLCB5ID0gbWFya2V0aW5nX3JvaSwgY29sb3IgPSBjb21wYW55KSkgKw0KICAgIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGFscGhhID0gMC42KSArICAgICAgICMgUHVudG9zIGRlIGRhdG9zDQogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkgKyAjIEzDrW5lYSBkZSB0ZW5kZW5jaWENCiAgICB0aGVtZV9taW5pbWFsKCkgKw0KICAgIGxhYnMoDQogICAgICB0aXRsZSA9ICJST0kgdnMgSW52ZXJzacOzbiBlbiBNYXJrZXRpbmciLA0KICAgICAgeCA9ICJJbnZlcnNpw7NuIGVuIE1hcmtldGluZyIsDQogICAgICB5ID0gIlJPSSINCiAgICApICsNCiAgICB0aGVtZSgNCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCAgIyBMZXllbmRhIGVuIGxhIHBhcnRlIGluZmVyaW9yDQogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIiksIA0KICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpDQogICAgKQ0KDQogICMgQ29udmVydGlyIGdyw6FmaWNvIGEgaW50ZXJhY3Rpdm8gY29uIHBsb3RseQ0KICByZXR1cm4oZ2dwbG90bHkocm9pX3Bsb3QpKQ0KfQ0KDQojIFZpc3VhbGl6YXIgYW7DoWxpc2lzIGRlIFJPSQ0KZ3JhZmljb19yb2kgPC0gYW5hbGlzaXNfcm9pKGRhdG9zX3ByZXApDQoNCiMgTW9zdHJhciBncsOhZmljbyBpbnRlcmFjdGl2bw0KZ3JhZmljb19yb2kNCg0KYGBgDQo=